package edu.core.testapp.client;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import edu.core.testapp.shared.Action;
import edu.core.testapp.shared.ChainAction;
import edu.core.testapp.shared.ElGamalKeyHolder;
import edu.core.testapp.shared.ElGamalKeyHolder.OpenKey;
import edu.core.testapp.shared.ElGamalKeyHolder.CloseKey;

public class Protect03Widget extends Composite {
	
	private final Protect03ServiceAsync service = GWT.create(Protect03Service.class);
	private final CommonServiceAsync common = GWT.create(CommonService.class);
	
	private final VerticalPanel mainPanel = new VerticalPanel();
	private final TextArea taFrom = new TextArea();
	private final TextArea taFromBase64 = new TextArea();
	private final TextArea taTo = new TextArea();
	private final TextArea taToBase64 = new TextArea();
	private final Button btnGenerate = new Button("Generate Keys");
	private final Button btnToBase64 = new Button("To Base 64");
	private final Button btnFromBase64 = new Button("From Base 64");
	private final Button btnEncode = new Button("Encode");
	private final Button btnDecode = new Button("Decode");
	private final Button btnSwitch = new Button("Switch");
	
	private final TextBox tbG = new TextBox();
	private final TextBox tbP = new TextBox();
	private final TextBox tbY = new TextBox();
	private final TextBox tbX = new TextBox();
	
	private final Label error = new Label();
	
	public Protect03Widget() {
		
		initHandlers();
		initComponents();

		initWidget(mainPanel);
		
	}
	
	private void initHandlers() {
		
		btnGenerate.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				
				tbG.setText("");
				tbP.setText("");
				tbY.setText("");
				tbX.setText("");
				error.setText("");
				
				service.generateKeys(new AsyncCallback<ElGamalKeyHolder>() {
					
					@Override
					public void onSuccess(ElGamalKeyHolder result) {

						tbG.setText(result.getOpenKey().getG());
						tbP.setText(result.getOpenKey().getP());
						tbY.setText(result.getOpenKey().getY());
						tbX.setText(result.getCloseKey().getX());
					}
					
					@Override
					public void onFailure(Throwable caught) {
						
						error.setText(caught.getMessage());
					}
				});
			}
		});
		
		btnEncode.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				(new PrepareEncodeAction()).execute();
			}
		});
		
		btnSwitch.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				String temp = taTo.getText();
				taTo.setText(taFrom.getText());
				taFrom.setText(temp);
				
				temp = taToBase64.getText();
				taToBase64.setText(taFromBase64.getText());
				taFromBase64.setText(temp);
			}
		});
		
		btnDecode.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				(new PrepareDecodeAction()).execute();
			}
		});
		
		btnToBase64.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				(new ToBase64Action()).execute();
			}
		});
		
		btnFromBase64.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				(new FromBase64Action()).execute();
			}
		});
		
	}
	
	private void encode() {
	}
	
	private void decode() {
	}
	
	private void fromBase64() {
		error.setText("");
		
		common.base64ToString(taToBase64.getText(), new AsyncCallback<String>() {
			
			@Override
			public void onFailure(Throwable caught) {
				error.setText(caught.getMessage());
			}
			
			@Override
			public void onSuccess(String result) {
				taTo.setText(result);
			}
		});
	}
	
	private void initComponents() {
		
		mainPanel.add(error);
		
		mainPanel.add(new Label("Open Key"));
		
		FlexTable ft = null;
		
		ft = new FlexTable();
		ft.setWidget(0, 0, new Label("G = "));
		ft.setWidget(1, 0, new Label("P = "));
		ft.setWidget(2, 0, new Label("Y = "));
		
		tbG.setWidth("250px");
		tbP.setWidth("250px");
		tbY.setWidth("250px");
		
		ft.setWidget(0, 1, tbG);
		ft.setWidget(1, 1, tbP);
		ft.setWidget(2, 1, tbY);
		
		mainPanel.add(ft);
		
		mainPanel.add(new Label("Close Key"));
		
		ft = new FlexTable();
		ft.setWidget(0, 0, new Label("Y = "));
		ft.setWidget(0, 1, tbX);
		
		tbX.setWidth("250px");
		
		mainPanel.add(ft);
		
		mainPanel.add(btnGenerate);

		mainPanel.add(new Label("From"));
		mainPanel.add(taFrom);
		mainPanel.add(new Label("From Base 64"));
		mainPanel.add(taFromBase64);
		mainPanel.add(new Label("To Base 64"));
		mainPanel.add(taToBase64);
		mainPanel.add(new Label("To"));
		mainPanel.add(taTo);
		
		taFrom.setWidth("300px");
		taFromBase64.setWidth("300px");
		taToBase64.setWidth("300px");
		taTo.setWidth("300px");
		taFrom.setHeight("50px");
		taFromBase64.setHeight("50px");
		taToBase64.setHeight("50px");
		taTo.setHeight("50px");
		
		HorizontalPanel hp = new HorizontalPanel();
		hp.add(btnToBase64);
		hp.add(btnEncode);
		hp.add(btnDecode);
		hp.add(btnFromBase64);
		hp.add(btnSwitch);
		
		mainPanel.add(hp);
		
	}
	
	private class ToBase64Action implements Action {
		
		@Override
		public boolean execute() {
			error.setText("");
			taFromBase64.setText("");
			common.stringToBase64(taFrom.getText(), new AsyncCallback<String>() {
				
				@Override
				public void onFailure(Throwable caught) {
					error.setText(caught.getMessage());
				}
				
				@Override
				public void onSuccess(String result) {
					taFromBase64.setText(result);
				}
			});
			
			return error.getText().isEmpty();
		}
	}
	
	private class FromBase64Action implements Action {
		
		@Override
		public boolean execute() {
			
			error.setText("");
			taTo.setText("");
			common.base64ToString(taToBase64.getText(), new AsyncCallback<String>() {
				
				@Override
				public void onFailure(Throwable caught) {
					error.setText(caught.getMessage());
				}
				
				@Override
				public void onSuccess(String result) {
					taTo.setText(result);
				}
			});
			
			return error.getText().isEmpty();
		}
	}
	
	private class EncodeAction implements Action {
		
		@Override
		public boolean  execute() {
			error.setText("");
			
			ElGamalKeyHolder kh = new ElGamalKeyHolder(
					new OpenKey(
							tbP.getText(),
							tbG.getText(),
							tbY.getText()
							),
					new CloseKey(
							tbX.getText()
							)
					);
					
			service.encodeBase64(taFromBase64.getText(), kh, new AsyncCallback<String>() {
				
				@Override
				public void onFailure(Throwable caught) {
					error.setText(caught.getMessage());
				}
				
				@Override
				public void onSuccess(String result) {
					taToBase64.setText(result);
					(new FromBase64Action()).execute();
				}
			});
			
			return error.getText().isEmpty();
		}
	}
	
	public class DecodeAction implements Action {
		
		@Override
		public boolean execute() {
			error.setText("");
			
			ElGamalKeyHolder kh = new ElGamalKeyHolder(
					new OpenKey(
							tbP.getText(),
							tbG.getText(),
							tbY.getText()
							),
					new CloseKey(
							tbX.getText()
							)
					);
					
			service.decodeBase64(taFromBase64.getText(), kh, new AsyncCallback<String>() {
				
				@Override
				public void onFailure(Throwable caught) {
					error.setText(caught.getMessage());
				}
				
				@Override
				public void onSuccess(String result) {
					taToBase64.setText(result);
					(new FromBase64Action()).execute();
				}
			});

			return error.getText().isEmpty();
		}
	}
	
	public class PrepareEncodeAction implements Action {
		
		@Override
		public boolean execute() {
			error.setText("");
			if (!taFrom.getText().isEmpty()) {
				common.stringToBase64(taFrom.getText(), new AsyncCallback<String>() {
					
					@Override
					public void onFailure(Throwable caught) {
						error.setText(caught.getMessage());
					}
					
					@Override
					public void onSuccess(String result) {
						taFromBase64.setText(result);
						(new EncodeAction()).execute();
					}
				});
			} else if (!taFromBase64.getText().isEmpty()) {
				common.base64ToString(taFromBase64.getText(), new AsyncCallback<String>() {

					@Override
					public void onFailure(Throwable caught) {
						error.setText(caught.getMessage());
					}

					@Override
					public void onSuccess(String result) {
						taFrom.setText(result);
						(new EncodeAction()).execute();
					}
				});
			} else {
				error.setText("Source text is not set.");
			}
			
			return error.getText().isEmpty();
		}
	}
	
	public class PrepareDecodeAction implements Action {
		
		@Override
		public boolean execute() {
			error.setText("");
			if (!taFromBase64.getText().isEmpty()) {
				common.base64ToString(taFromBase64.getText(), new AsyncCallback<String>() {

					@Override
					public void onFailure(Throwable caught) {
						error.setText(caught.getMessage());
					}

					@Override
					public void onSuccess(String result) {
						taFrom.setText(result);
						(new DecodeAction()).execute();
					}
				});
			} else if (!taFrom.getText().isEmpty()) {
				common.stringToBase64(taFrom.getText(), new AsyncCallback<String>() {
					
					@Override
					public void onFailure(Throwable caught) {
						error.setText(caught.getMessage());
					}
					
					@Override
					public void onSuccess(String result) {
						taFromBase64.setText(result);
						(new DecodeAction()).execute();
					}
				});
			} else {
				error.setText("Source text is not set.");
			}
			
			return error.getText().isEmpty();
		}
	}

}
